__author__ = 'JackSong'

import paramiko
import logging
import chardet
from ioloop import IOloop
from tornado.websocket import WebSocketClosedError
from paramiko.ssh_exception import AuthenticationException, SSHException, BadHostKeyException


class Bridge(object):
    def __init__(self, websocket):
        self._websocket = websocket
        self._shell = None
        self._fd = 0
        self.ssh = paramiko.SSHClient()
        self._status = False

    @property
    def fd(self):
        return self._fd

    @property
    def status(self):
        return self._status

    @property
    def websocket(self):
        return self._websocket

    def executor(self, fn, *args):
        return self.websocket.executor.submit(fn, *args)

    @property
    def shell(self):
        return self._shell

    def open(self, data={}):
        from utils.tools import PrpcryptInitData
        self.ssh.load_system_host_keys()
        self.ssh.set_missing_host_key_policy(
            paramiko.AutoAddPolicy())
        data = PrpcryptInitData(**data)
        self.connect(data)

    def connect(self, data):
        try:
            self.ssh.connect(
                hostname=data.hostname,
                port=int(data.port),
                username=data.username,
                password=data.password,
                timeout=3,
                gss_auth=False,
                gss_kex=False,
                gss_deleg_creds=False,
            )
        except AuthenticationException:
            raise Exception("auth failed user:%s ,passwd:%s" %
                            (data.username, data.password))
        except BadHostKeyException:
            raise Exception('Unable to establish a link:%s', data.hostname)
        except SSHException:
            raise Exception("could not connect to host:%s:%s" %
                            (data.username, data.password))
        self.establish()

    def establish(self, term="xterm"):
        self._shell = self.ssh.invoke_shell(term)
        self._shell.setblocking(0)
        self._fd = self._shell.fileno()
        self._status = True
        IOloop.instance().register(self)

    def trans_forward(self, data=""):
        if self._shell:
            try:
                self._shell.send(data)
                return True
            except:
                return False
        else:
            return False

    def trans_back(self, result):
        if self._websocket:
            try:
                detect = chardet.detect(result)
                encoding = detect.get('encoding')
                if result and encoding and encoding != 'utf-8':
                    result = result.decode(encoding).encode("utf-8")
                self._websocket.write_message(result)
                if result.strip() == 'logout':
                    return False
                return True
            except WebSocketClosedError as e:
                logging.debug(e)
                return False


    def destroy(self):
        self._websocket.close()
        self.ssh.close()
        IOloop.instance().remove_handler(self.fd)
        logging.info('close connect %s' % (id(self),))
